	
#include "fig_bullet_manager.h"
#include "fig_craft.h"
#include "fighter.h"
#include "fig_bullet_rocket.h"
#include "fig_rocket_topido.h"
#include "fig_sounds.h"
#include "fig_bullet_sfx.h"

#include "math/facing.h"
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    
#include <cassert>


FIGBulletManager::FIGBulletManager(FIGBullet::BULLET_TYPES Type, 
								   int GroupCount,
								   float BulletFrequency,
								   float DelayAfterBulletGroup,
								   bool IsPlayer
								   ) : 
										m_Type(Type),
										m_GroupCount(GroupCount),
										m_GroupIndex(0),
										m_BulletFrequency(BulletFrequency),
										m_BulletDelayCounter(0.0f),
										m_DelayAfterBulletGroup(DelayAfterBulletGroup),
										m_GroupDelayCounter(0.0f),
										m_IsPlayerCraft(IsPlayer)

{
	
}


	



void			FIGBulletManager::Render( const math::Vec2& Offset,float Scale)
{
	for(unsigned int i = 0; i < m_Bullets.size(); i++)
	{
		FIGBullet*  Bullet = m_Bullets[i];
		Bullet->Render(Offset,Scale);
	}
}

void			FIGBulletManager::RenderDebug(const math::Vec2& Offset, float Scale)
{
	for(unsigned int i = 0; i < m_Bullets.size(); i++)
	{
		FIGBullet*  Bullet = m_Bullets[i];
		Bullet->RenderDebug(Offset,Scale);
	}
}

void			FIGBulletManager::Tick(float dt)
{
	for(unsigned int i = 0; i < m_Bullets.size(); i++)
	{
		FIGBullet*  Bullet = m_Bullets[i];
		Bullet->Tick(dt);
	}

	
}

void		FIGBulletManager::ShootTick(
										FIGLifeObj* pShooter,
										const math::Vec2& ShootPos,
										float dt,
										const math::Vec2& TargetDir,
										FIGBullet::SHOOT_STYLES ShootStyle,
										int SoundSFXIndex
										)
{
	math::Vec2 TempDir = TargetDir;
	math::Vec2 Pos = ShootPos;

	if(m_GroupDelayCounter > 0)
	{
		m_GroupDelayCounter -= dt;
		return;
	}

	m_BulletDelayCounter += dt;
	if(m_BulletDelayCounter > m_BulletFrequency)
	{
		m_BulletDelayCounter = 0;
		FIGSounds::Instance().PlaySoundSFX((FIGSounds::SOUND_NAMES)SoundSFXIndex);

		switch(ShootStyle)
		{
			case FIGBullet::SHOOT_STYLES_SINGLE:
				Spawn(  
						pShooter,
						Pos, 
						FIGBullet::STARTPOS_LEFT,
						TargetDir
						);
			break;
			case FIGBullet::SHOOT_STYLES_ROCKET2:
			case FIGBullet::SHOOT_STYLES_DOUBLE:
				TempDir = TargetDir;
				TempDir.Rotate(90.0f);
				TempDir *= 0.025f;

				Spawn(  
						pShooter,
						Pos - TempDir ,
						FIGBullet::STARTPOS_LEFT,
						TargetDir
						);
				Spawn(  
						pShooter,
						Pos + TempDir ,
						FIGBullet::STARTPOS_RIGHT,
						TargetDir
						);
			break;
			case FIGBullet::SHOOT_STYLES_TRIPPLE:
				 Spawn(  
						pShooter,
						Pos,
						FIGBullet::STARTPOS_MIDDLE,
						TargetDir
						);
				ShootToDegree(pShooter, Pos, 10);
				ShootToDegree(pShooter, Pos, -10);
			break;

			case FIGBullet::SHOOT_STYLES_TRIPPLE_STRAIGHT:
				TempDir = TargetDir;
				TempDir.Rotate(90.0f);
				TempDir *= 0.03f;
				Spawn(  
						pShooter,
						Pos - TempDir ,
						FIGBullet::STARTPOS_LEFT,
						TargetDir
						);
				Spawn(  
						pShooter,
						Pos + TempDir ,
						FIGBullet::STARTPOS_RIGHT,
						TargetDir
						);
				Spawn(  
						pShooter,
						Pos,
						FIGBullet::STARTPOS_RIGHT,
						TargetDir
						);
				break;

			case FIGBullet::SHOOT_STYLES_RAMBO_5:
				RomboShoot5(pShooter, ShootPos);
				break;
			case FIGBullet::SHOOT_STYLES_RAMBO_4:
				RomboShoot4(pShooter, ShootPos);
				break;
			case FIGBullet::SHOOT_STYLES_RAMBO_6:
				RomboShoot6(pShooter, ShootPos);													
				break;
			
			case FIGBullet::SHOOT_STYLES_ROCKET4:
			{
				FIGBullet* pBullet;

				Spawn( 
						pShooter,
						Pos + math::Vec2( 0 ,0) ,
						FIGBullet::STARTPOS_LEFT,
						TargetDir
						);
				
				Spawn(
						pShooter,
						Pos + math::Vec2(0 ,0) ,
						FIGBullet::STARTPOS_RIGHT,
						TargetDir
						);				

				pBullet = Spawn(  
						pShooter,
						Pos + math::Vec2( -0.025f ,0.025f) ,
						FIGBullet::STARTPOS_LEFT,
						TargetDir
						);
				pBullet->SetDelay(0.1f);

				
				pBullet = Spawn(  
						pShooter,
						Pos + math::Vec2(0.025f ,0.025f) ,
						FIGBullet::STARTPOS_RIGHT,
						TargetDir
						);
				pBullet->SetDelay(0.1f);

			}
			break;
			case FIGBullet::SHOOT_STYLES_ROCKET6:
			{
				FIGBullet* pBullet;
				// outward
				pBullet = Spawn(  
							pShooter,
							Pos + math::Vec2( 0.0f ,0.025f) ,
							FIGBullet::STARTPOS_LEFT,
							TargetDir
							);
				pBullet->SetDelay(0.1f);

				pBullet = Spawn(  
							pShooter,
							Pos + math::Vec2(0.0f ,0.025f) ,
							FIGBullet::STARTPOS_RIGHT,
							TargetDir
							);
				pBullet->SetDelay(0.1f);

				Spawn(  
						pShooter,
						Pos + math::Vec2( -0.03f ,0) ,
						FIGBullet::STARTPOS_LEFT,
						TargetDir
						);
				Spawn(  
						pShooter,
						Pos + math::Vec2(0.03f ,0) ,
						FIGBullet::STARTPOS_RIGHT,
						TargetDir
						);

				pBullet = Spawn(  
						pShooter,
						Pos + math::Vec2( -0.06f ,0.025f) ,
						FIGBullet::STARTPOS_LEFT,
						TargetDir
						);
				pBullet->SetDelay(0.2f);

				pBullet = Spawn(   
						pShooter,
						Pos + math::Vec2(0.06f ,0.025f) ,
						FIGBullet::STARTPOS_RIGHT,
						TargetDir
						);
				pBullet->SetDelay(0.2f);
			}
			break;

			case FIGBullet::SHOOT_STYLES_SHAPE_TRIANGLE:
				SpawnBulletsShapeTriangle(	pShooter,
											Pos, 											
											TargetDir);
			break;

			case FIGBullet::SHOOT_STYLES_SHAPE_CIRCLE:
				SpawnBulletsShapeCircle(
										pShooter,
										Pos,
										TargetDir);
			break;
		}

		m_GroupIndex++;
		if(m_GroupIndex >= m_GroupCount)
		{
			m_GroupIndex = 0;
			m_GroupDelayCounter = m_DelayAfterBulletGroup;
		}
		
	}
}



void		FIGBulletManager::Clear()
{
	for(unsigned int i = 0; i < m_Bullets.size(); i++)
	{
		FIGBullet*  Bullet = m_Bullets[i];
		Bullet->Clear();
	}
	
	
	for( int i = (int)m_Bullets.size() - 1; i >= 0; i--)
	{
		FIGBullet*  pBullet = m_Bullets[i];
		UTIL_SAFE_DELETE(pBullet);
	}
	m_Bullets.resize(0);
}

void			FIGBulletManager::DieAll()
{
	for(unsigned int i = 0; i < m_Bullets.size(); i++)
	{
		FIGBullet*  Bullet = m_Bullets[i];
		Bullet->Kill();
	}
}

FIGBullet*			FIGBulletManager::Spawn(
										FIGLifeObj*	pShooter,
										const math::Vec2& Pos , 
										FIGBullet::STARTPOS StartDir,
										const math::Vec2& TargetDir
										)
{

	for( int i = 0; i < (int)m_Bullets.size(); i++)
	{
		FIGBullet*  Bullet = m_Bullets[i];
		if(!Bullet->IsAlive())
		{
			Bullet->ReSpawn(Pos,StartDir,TargetDir);
			return Bullet;
		}
	}

	FIGBullet* pBullet = NULL;

	
	const float P_N_POWER = 1.0f;
	const float P_R_POWER = 10.0f;
	const float P_H_POWER = 6.0f;
								 
	const float E_POWER_1 = 1.0f;
	const float E_POWER_2 = 2.0f;

	
	switch(m_Type)
	{
		case FIGBullet::BULLET_TYPE_PLAYER_BLUE:
			pBullet = new FIGBullet(0.9f,
									false,
									P_N_POWER + ( P_N_POWER * 0.3f),
									FIGBullet::BULLET_TYPE_PLAYER_BLUE);			
		break;
		case FIGBullet::BULLET_TYPE_PLAYER_GREEN:
			pBullet = new FIGBullet(0.7f,false,P_N_POWER,FIGBullet::BULLET_TYPE_PLAYER_GREEN);			
		break;

		case FIGBullet::BULLET_TYPE_PLAYER_RED:
			pBullet = new FIGBullet(0.7f,false,P_N_POWER,FIGBullet::BULLET_TYPE_PLAYER_RED);		
		break;

		case FIGBullet::BULLET_TYPE_PLAYER_ROCKET:
			pBullet = new FIGBulletRocket(P_R_POWER,false);
		break;

		case FIGBullet::BULLET_TYPE_PLAYER_TOPIDO:
			pBullet = new FIGRocketTopido(P_H_POWER);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_ROTATE:
			pBullet = new FIGBullet(0.3f,true,E_POWER_1,FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_ROTATE);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_GLOW:
			pBullet = new FIGBullet(0.4f,false,E_POWER_2,FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_GLOW);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_DOUBLELAYER:
			pBullet = new FIGBullet(0.25f,false,E_POWER_1,FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_DOUBLELAYER);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_TRIPPLELAYER:
			pBullet = new FIGBullet(0.2f,false,E_POWER_2,FIGBullet::BULLET_TYPE_ENEMY_CIRCLE_TRIPPLELAYER);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_LONG_CYAN:
			pBullet = new FIGBullet(0.4f,false,E_POWER_1,FIGBullet::BULLET_TYPE_ENEMY_LONG_CYAN);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_LONG_GREEN:
			pBullet = new FIGBullet(0.42f,false,E_POWER_1,FIGBullet::BULLET_TYPE_ENEMY_LONG_GREEN);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_LONG_RED:
			pBullet = new FIGBullet(0.45f,false,E_POWER_1,FIGBullet::BULLET_TYPE_ENEMY_LONG_RED);
		break;

		case FIGBullet::BULLET_TYPE_ENEMY_LONG_YELLOW:
			pBullet = new FIGBullet(0.43f,false,E_POWER_1,FIGBullet::BULLET_TYPE_ENEMY_LONG_YELLOW);
		break;  

		
					
		case FIGBullet::BULLET_TYPE_EFFECT_FIRE:
			pBullet = new FIGBulletSfx(		0.30f,
											FIGSfx::BULLET_FIRE
											); 
			
		break;

		case FIGBullet::BULLET_TYPES_ENEMY_ROCKET:
			pBullet = new FIGBulletRocket( 5.0f,true);
			((FIGBulletRocket*)pBullet)->JustGoForward();
		break;

		default:
			break;
	}

	if(pBullet)
	{
		std::string SpriteName = FIGBullet::GetSpriteNameByType(m_Type);
		if(!SpriteName.empty())
			pBullet->Load(SpriteName);
		m_Bullets.push_back(pBullet);
		pBullet->ReSpawn(Pos,StartDir,TargetDir);
		return pBullet;
	}

	

	return NULL;
	
	
}


int			FIGBulletManager::GetCount() const
{
	return (int)m_Bullets.size();
}

FIGBullet*	FIGBulletManager::GetBulletByIndex(int Index)
{
	return m_Bullets[Index];
	
}



FIGBullet*	FIGBulletManager::ShootToDegree(FIGLifeObj* pShooter, const math::Vec2& Pos, float Degree)
{
	if(!m_IsPlayerCraft)
		Degree += 180;

	if(Degree > 360)
		Degree = Degree - 360;

	math::Vec2 Dir = math::Facing::VectorFromAngle(Degree);
	return Spawn(pShooter, Pos,FIGBullet::STARTPOS_MIDDLE , Dir);
}


void	FIGBulletManager::ShootToAllDir(const math::Vec2& Pos)
{
	int Degree = 0;
	while(Degree <= 360)
	{
		FIGBullet* pBullet = ShootToDegree(NULL, Pos,(float)Degree);
		Degree += 45;

		if(pBullet)
		{
			if(pBullet->GetType() == FIGBullet::BULLET_TYPE_PLAYER_ROCKET)
			{
				((FIGBulletRocket*)pBullet)->SetState(FIGBulletRocket::STATE_GOFORWARD);
			}
		}
	}
	

}
